package envelopes

import (
	"context"
	"gitee.com/wm1998/account/core/accounts"
	acservice "gitee.com/wm1998/account/services"
	"gitee.com/wm1998/infra/base"
	"gitee.com/wm1998/resk/services"
	"github.com/tietang/dbx"
	"path"
)

// 发红包业务领域层实现
func (d *goodsDomain) SendOut(goods services.RedEnvelopeGoodsDTO) (activity *services.RedEnvelopeActivity, err error) {

	// 创建红包商品
	d.Create(goods)

	// 创建红包活动
	activity = new(services.RedEnvelopeActivity)

	//红包链接，格式：http://域名/v1/envelope/{id}/link/
	link := base.GetEnvelopeActivityLink() // 从系统配置文件中获取红包活动-活动链接地址
	domain := base.GetEnvelopeDomain()     // 从系统配置文件中获取红包活动-活动链接的域名地址
	activity.Link = path.Join(domain, link, d.EnvelopeNo)

	accountDomain := accounts.NewAccountDomain() // 构建资金账户-业务领域模型

	err = base.Tx(func(runner *dbx.TxRunner) (err error) {
		//保存红包商品
		// 【事务逻辑重点要求】：保存红包商品和红包金额的支付必须要保证全部成功或者全部失败，即：保证这2个事务的原子性操作
		ctx := base.WithValueContext(context.Background(), runner) // 将runner绑定到context.Background()这个顶级上下文对象里
		// 跨方法调用保存到红包操作，传递context上下文的作用：与后边的红包资金账户转账这2个操作在同一个事务里以实现事务原子性操作
		id, err := d.Save(ctx) // 保存到红包
		if id <= 0 || err != nil {
			return err
		}

		//红包金额支付，过程有如下3步骤：
		//1. 需要定义红包中间商的红包资金账户到配置文件中，事先初始化到资金账户表中
		//2. 从红包发送人的资金账户中扣减红包金额，再把红包金额从红包发送人的资金账户里扣除

		/*=========================	把红包金额从红包发送人的资金账户里扣除	开始	==========================*/
		body := acservice.TradeParticipator{ // 构建转账接口-输入DTO的子对象：交易主体对象
			AccountNo: goods.AccountNo,
			UserId:    goods.UserId,
			Username:  goods.Username,
		}

		systemAccount := base.GetSystemAccount() // 交易目标对象是系统红包中间商的资金账户
		target := acservice.TradeParticipator{   // 交易目标对象
			AccountNo: systemAccount.AccountNo,
			Username:  systemAccount.Username,
			UserId:    systemAccount.UserId,
		}

		transfer := acservice.AccountTransferDTO{ // 构建转账DTO
			TradeBody:   body,
			TradeTarget: target,
			TradeNo:     d.EnvelopeNo,
			Amount:      d.Amount,
			ChangeType:  acservice.EnvelopeOutgoing,
			ChangeFlag:  acservice.FlagTransferOut,
			Decs:        "红包金额支付",
		}
		// 跨方法调用资金账户转账，使上边的save()保存到红包操作与下边的红包资金账户转账这2个操作在同一个事务里以实现事务原子性操作
		status, err := accountDomain.TransferWithContextTx(ctx, transfer) // 红包资金账户转账
		if status == acservice.TransferedStatusSuccess {
			return nil
		} else {
			return err // 修复Bug
		}
		/*=========================	把红包金额从红包发送人的资金账户里扣除	结束	==========================*/

		//3. 将扣减的红包总金额转入红包中间商的红包资金账户-入账
		transfer = acservice.AccountTransferDTO{
			TradeBody:   target,
			TradeTarget: body,
			TradeNo:     d.EnvelopeNo,
			Amount:      d.Amount,
			ChangeType:  acservice.EnvelopeIncoming,
			ChangeFlag:  acservice.FlagTransferIn,
			Decs:        "红包金额转入",
		}
		status, err = accountDomain.TransferWithContextTx(ctx, transfer)
		if status == acservice.TransferedStatusSuccess {
			return nil
		}
		return err
	})
	if err != nil {
		return nil, err
	}

	//扣减金额没有问题，返回红包商品活动
	activity.RedEnvelopeGoodsDTO = *d.RedEnvelopeGoods.ToDTO()

	return activity, err
}
